//========================================================================
// *作者：海盗猫  主页：ilplay.com
// *脚本：HDMPackageHotfixBase
// *描述：
// *?2021 MYJL . All rights reserved.
//* ======================================================================
using HybridCLR;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

namespace HDMCode.Hotfix
{
    public class HDMPackageHotfixBase : HDMPackageHotfixDate
    {
        /// <summary>
        /// 当前服务器资源版本号
        /// </summary>
        private string serverVesion = default;

        /// <summary>
        /// 获取包体
        /// </summary>
        private YooAsset.ResourcePackage GetPackage(string PackName)
        {
            YooAsset.ResourcePackage package = null;
            package = YooAsset.YooAssets.TryGetPackage(PackName);
            if (package is null)
                package = YooAsset.YooAssets.CreatePackage(PackName);
            if (package is null)
                Debug.Log($"通过包名获取包体失败!  包名：{PackName}");
            return package;
        }

        /// <summary>
        /// 编辑器下执行初始化
        /// </summary>
        /// <param name="packageName"></param>
        /// <param name="errorCallBack"></param>
        /// <returns></returns>
        protected IEnumerator EditorInitializePackage(string mianPackName, string subPackName, CoroutineSimulationCallback SimulationCallBack) 
        {
            if (!YooAsset.YooAssets.Initialized) YooAsset.YooAssets.Initialize();
            var editorinitParameters = new YooAsset.EditorSimulateModeParameters();
            editorinitParameters.SimulateManifestFilePath = YooAsset.EditorSimulateModeHelper.SimulateBuild(YooAsset.EDefaultBuildPipeline.BuiltinBuildPipeline, mianPackName);
            yield return GetPackage(mianPackName).InitializeAsync(editorinitParameters);
            editorinitParameters.SimulateManifestFilePath = YooAsset.EditorSimulateModeHelper.SimulateBuild(YooAsset.EDefaultBuildPipeline.RawFileBuildPipeline, subPackName);
            yield return GetPackage(subPackName).InitializeAsync(editorinitParameters);
            SimulationCallBack?.Invoke(GetPackage(mianPackName), GetPackage(subPackName));
        }

        /// <summary>
        /// 模拟模式下执行初始化
        /// </summary>
        /// <param name="packageName"></param>
        /// <param name="errorCallBack"></param>
        /// <returns></returns>
        protected IEnumerator OfflineInitializePackage(string packageName, CoroutineCallback errorCallBack, CoroutineVerifyCallback updateCallBack, CoroutineVerifyCallback notUpdateCallBack)
        {
            if (!YooAsset.YooAssets.Initialized) YooAsset.YooAssets.Initialize();
            var offlineInitParameters = new YooAsset.OfflinePlayModeParameters();
            yield return GetPackage(packageName).InitializeAsync(offlineInitParameters);
            yield return UpdatePackageVersion(packageName, errorCallBack);
            yield return UpdatePackageManifest(packageName, errorCallBack);
            yield return UpdateDownloadInfo(packageName, updateCallBack, notUpdateCallBack);
        }

        /// <summary>
        /// 实机模式下初始化资源信息
        /// </summary>
        /// <returns></returns>
        protected IEnumerator InitializePackage(string packageName, CoroutineCallback errorCallBack, CoroutineVerifyCallback updateCallBack, CoroutineVerifyCallback notUpdateCallBack)
        {
            if (!YooAsset.YooAssets.Initialized) YooAsset.YooAssets.Initialize();
            var initParameters = new YooAsset.HostPlayModeParameters();
            initParameters.BuildinQueryServices = new GameQueryServices();
            initParameters.DecryptionServices = new FileOffsetDecryption();
            initParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
            var initOperation = GetPackage(packageName).InitializeAsync(initParameters);
            yield return initOperation;
            if (initOperation.Status != YooAsset.EOperationStatus.Succeed)
                errorCallBack?.Invoke("初始化包体失败");
            yield return UpdatePackageVersion(packageName, errorCallBack);
            yield return UpdatePackageManifest(packageName, errorCallBack);
            yield return UpdateDownloadInfo(packageName, updateCallBack, notUpdateCallBack);
        }

        /// <summary>
        /// 获取并更新版本信息
        /// </summary>
        /// <returns></returns>
        protected IEnumerator UpdatePackageVersion(string packageName, CoroutineCallback errorCallBack)
        {
            var package = GetPackage(packageName);
            var operation = package.UpdatePackageVersionAsync();
            yield return operation;
            if (operation.Status == YooAsset.EOperationStatus.Succeed)
                serverVesion = operation.PackageVersion;
            else
                errorCallBack?.Invoke(operation.Error);
        }

        /// <summary>
        /// 获取并更新资源清单
        /// </summary>
        private IEnumerator UpdatePackageManifest(string packageName, CoroutineCallback errorCallBack)
        {
            var package = GetPackage(packageName);
            var operation = package.UpdatePackageManifestAsync(serverVesion, true);
            yield return operation;
            if (operation.Status != YooAsset.EOperationStatus.Succeed)
                errorCallBack(operation.Error);
        }


        /// <summary>
        /// 获取需要更新的详细信息
        /// </summary>
        private IEnumerator UpdateDownloadInfo(string packageName, CoroutineVerifyCallback updateCallBack, CoroutineVerifyCallback notUpdateCallBack)
        {
            var package = GetPackage(packageName);
            var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
            if (downloader.TotalDownloadCount == 0)
            {
                notUpdateCallBack?.Invoke(new AssetsDownloadInfo()
                {
                    package = package,
                    totalDownloadCount = 0,
                    totalDownloadBytes = 0
                });
            }
            else
            {
                updateCallBack?.Invoke(new AssetsDownloadInfo()
                {
                    package = package,
                    totalDownloadCount = downloader.TotalDownloadCount,
                    totalDownloadBytes = downloader.TotalDownloadBytes
                });
            }
            yield return null;
        }

        /// <summary>
        /// 执行资源下载
        /// </summary>
        /// <returns></returns>
        protected IEnumerator RunAssetsDownload(string packageName, YooAsset.DownloaderOperation.OnDownloadError onDownloadError, YooAsset.DownloaderOperation.OnDownloadProgress onDownloadProgress, YooAsset.DownloaderOperation.OnDownloadOver onDownloadOver, YooAsset.DownloaderOperation.OnStartDownloadFile onStartDownloadFile, CoroutineCallback successCallback)
        {
            var package = GetPackage(packageName);
            var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
            downloader.OnDownloadErrorCallback = onDownloadError;
            downloader.OnDownloadProgressCallback = onDownloadProgress;
            downloader.OnDownloadOverCallback = onDownloadOver;
            downloader.OnStartDownloadFileCallback = onStartDownloadFile;
            downloader.BeginDownload();
            yield return downloader;
            if (downloader.Status == YooAsset.EOperationStatus.Succeed)
            {
                package.ClearUnusedCacheFilesAsync();
                successCallback?.Invoke(downloader.PackageName);
            }
            else
            {
                onDownloadError?.Invoke(downloader.PackageName, downloader.Error);
            }
        }

        /// <summary>
        /// 执行资源下载
        /// </summary>
        /// <returns></returns>
        protected IEnumerator RunAssetsDownloads(string mainPackageName, string subPackageName, YooAsset.DownloaderOperation.OnDownloadError onDownloadError, YooAsset.DownloaderOperation.OnDownloadProgress onDownloadMainProgress, YooAsset.DownloaderOperation.OnDownloadProgress onDownloadSubProgress, YooAsset.DownloaderOperation.OnDownloadOver onDownloadOver, YooAsset.DownloaderOperation.OnStartDownloadFile onStartDownloadFile, CoroutineCallback successCallback)
        {
            var mainPackage = GetPackage(mainPackageName);
            mainPackageDownloader = mainPackage.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
            mainPackageDownloader.OnDownloadErrorCallback = onDownloadError;
            mainPackageDownloader.OnDownloadProgressCallback = onDownloadMainProgress;
            mainPackageDownloader.OnDownloadOverCallback = onDownloadOver;
            mainPackageDownloader.OnStartDownloadFileCallback = onStartDownloadFile;
            mainPackageDownloader.BeginDownload();
            yield return mainPackageDownloader;

            var subPackage = GetPackage(subPackageName);
            subPackageDownloader = subPackage.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
            subPackageDownloader.OnDownloadErrorCallback = onDownloadError;
            subPackageDownloader.OnDownloadProgressCallback = onDownloadSubProgress;
            subPackageDownloader.OnDownloadOverCallback = onDownloadOver;
            subPackageDownloader.OnStartDownloadFileCallback = onStartDownloadFile;
            subPackageDownloader.BeginDownload();
            yield return subPackageDownloader;

            if (mainPackageDownloader.Status == YooAsset.EOperationStatus.Succeed && subPackageDownloader.Status == YooAsset.EOperationStatus.Succeed)
            {
                mainPackage.ClearUnusedCacheFilesAsync();
                subPackage.ClearUnusedCacheFilesAsync();
                successCallback?.Invoke(mainPackageDownloader.PackageName);
            }
            else
            {
                onDownloadError?.Invoke(mainPackageDownloader.PackageName, mainPackageDownloader.Error);
            }
        }

        /// <summary>
        /// 加载元数据和热更新程序集
        /// </summary>
        /// <param name="hotAssembly">热更新程序集链表</param>
        /// <param name="mateAssembly">元数据程序集链表</param>
        /// <param name="callBack">加载完成回调</param>
        /// <returns></returns>
        protected IEnumerator LoadMateDate(List<string> hotAssembly, List<string> mateAssembly,System.Action callBack) 
        {
            foreach (var assembly in hotAssembly)
            {
                yield return HDMAssetsLoad.LoadFile(assembly, (result) => 
                {
                    Debug.Log($"热更新程序集加载中：{assembly}");
                    Assembly.Load(result);
                    HDMAssembly.hotFoxAssemblyDict.Add(assembly, result);
                });
            }

            foreach (var assembly in mateAssembly)
            {
                yield return HDMAssetsLoad.LoadFile(assembly, (result) =>
                {
                    Debug.Log($"元数据程序集加载中：{assembly}");
                    HDMAssembly.mateDateAssemblyDict.Add(assembly, result);
                    LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(result, HomologousImageMode.SuperSet);
                });
            }
            callBack?.Invoke();
        }
    }
}